package com.whg.shiro.config;

import com.whg.shiro.domain.PermissionModel;
import com.whg.shiro.domain.RoleModel;
import com.whg.shiro.domain.UserModel;
import com.whg.shiro.domain.vo.RoleVO;
import com.whg.shiro.domain.vo.UserRolesVO;
import com.whg.shiro.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.SimpleByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author whg
 * @create 2022/9/28 16:05
 * @description：自定义realm
 * shiro中提供了对认证信息和授权信息的缓存，
 * 默认是关闭认证信息缓存的，对于授权信息的缓存shiro默认开启的(因为授权的数据量大)
 */
public class CustomRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;


    /**
     * 用户鉴权时会调用
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权 doGetAuthorizationInfo");

        UserModel userModel = (UserModel)principalCollection.getPrimaryPrincipal();
        UserRolesVO vo = userService.findUserRolesByUserName(userModel.getUsername());
        //角色集合
        List<String> roleList = new ArrayList<>();
        //权限集合
        List<String> permissionList = new ArrayList<>();

        roleList = vo.getRoles().stream().map(obj -> {
            if(!CollectionUtils.isEmpty(obj.getPermissionModels())){
                permissionList.addAll(obj.getPermissionModels().stream()
                        .map(PermissionModel::getName).collect(Collectors.toList()));
            }
            return obj.getName();
        }).collect(Collectors.toList());

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRoles(roleList);
        simpleAuthorizationInfo.addStringPermissions(permissionList);

        return simpleAuthorizationInfo;
    }

    /**
     * 用户登录时会调用
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("认证 doGetAuthenticationInfo");

        String userName = (String)authenticationToken.getPrincipal();
        UserModel user = userService.findUserByName(userName);
        String password = user.getPassword();
        if(null == password || "".equals(password)){
            return null;
        }
        /*RoleModel role = new RoleModel();
        role.setName("admin");*/
        //密码加盐
        return new SimpleAuthenticationInfo(user,password, new MySimpleByteSource(user.getSalt()),this.getClass().getName());
        //密码加盐，但是ByteSource.Util.bytes方法返回的类型SimpleByteSource，没有实现Serializable接口，无法序列化，
        //所以，RedisCache的put方法会报错，序列化失败
        //return new SimpleAuthenticationInfo(user,password, ByteSource.Util.bytes(user.getSalt()),this.getClass().getName());
        //密码不加盐
        //return new SimpleAuthenticationInfo(user,password,this.getClass().getName());
    }
}
